-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add 'compare performance' view #3843
Conversation
Adds a dropdown with (at present) two options: sorting by delta and sorting by absolute delta.
This ensures we can use hooks after the check in the main component
A very hacky implementation that simply instantiates an empty `PerformanceOverviewScanner` as the "from" column (i.e. with all values empty). To see it in action, select a single query run in the query history and pick "Compare Performance" from the context menu. Then select the "Single run" option when prompted.
Only contains formatting changes
Predicate names can't be empty, but it can happen with the renaming feature added in the next commit.
13e78a6
to
ec223fa
Compare
ec223fa
to
aa528c6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks ok to me in general. I haven't tried running this. It also seems isolated, so that if there is a problem, it is unlikely to affect other features.
There are a few questions and comments inside. Mostly, I'd like to either remove all TODO
s and XXX
s and replace them with a simple comment. If you think you will go back later to fix them, then please create an issue to track it.
}; | ||
} | ||
|
||
protected onPanelDispose(): void {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to remove references to resultsView
and labelProvider
?
protected onPanelDispose(): void {} | |
protected onPanelDispose(): void { | |
this.resultsView = null; | |
this.labelProvider = null; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm...not sure what the lifecycle of the view is. Is there a single view
instance created for the entire extension, or is it one view per window that's opened?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The instance of this class persists across multiple open/close of the panel so I'd say we shouldn't dispose of these fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see how onPanelDispose
is called in the super class. Your implementation here is fine.
*/ | ||
export interface PerformanceComparisonDataFromLog { | ||
/** Names of predicates mentioned in the log */ | ||
names: string[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we expect the lengths of these arrays to be the same for all? If not, which ones will have different sizes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a more thorough description
/** | ||
* List of indices into the `names` array for which we have seen a cache hit. | ||
* | ||
* TODO: only count cache hits prior to first evaluation? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and below, if the TODO
is tracked in an issue, can you add the issue? If it's not tracked, can you remove the TODO
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove or resolve the TODOs 👍
For this one I went ahead and resolved it
singleItem: QueryHistoryInfo, | ||
multiSelect: QueryHistoryInfo[] | undefined, | ||
) { | ||
// TODO: reduce duplication with 'handleCompareWith' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same...and below.
multiSelect: QueryHistoryInfo[] | undefined, | ||
) { | ||
// TODO: reduce duplication with 'handleCompareWith' | ||
multiSelect ||= [singleItem]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a nice shortcut. I hadn't thought of that.
? allSelectedItems[1] | ||
: allSelectedItems[0]; | ||
if (otherItem.databaseName !== dbName) { | ||
throw new Error("Query databases must be the same."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: can you include the db names in this message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember why this condition is even here; it's possible we should just remove the restriction. I've asked @tausbn if he remembers why it's here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be fine with removing this. I have no recollection of why it would be necessary, and I don't think anything would blow up if you compare two different databases. At worst, you just get somewhat useless output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this snippet of code was copy/pasted from findOtherQueryToCompare
but isn't actually relevant for performance comparisons. I pushed a commit that removes the unnecessary check.
args.push(parseQName()); | ||
skipToken(","); | ||
} | ||
args.reverse(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the reverse
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment to clarify
Note that the tokens stream is parsed in reverse order. This is simpler, but may look confusing initially.
if (prefix != null) { | ||
result.push(prefix.abbreviate()); | ||
result.push("::"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is quite complex to me. It is combining prefix
from the closure with result
, a local variable. This function is complex enough that maybe VisitResult
should be a class and prefix
is passed in as a private field. Then this function can become a member of VisitResult
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is a matter of taste. Personally I find captured variables to be simpler to follow than fields as you can just jump to it to see what it is. This actually started out as a class, which I converted to a closure to simplify it. Do you feel strongly about doing this rewrite?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine by me. I can understand your perspective even if it is not how I would have written it. And it doesn't seem incorrect to me.
Restrict to Canary Co-authored-by: Andrew Eisenberg <[email protected]>
Co-authored-by: Andrew Eisenberg <[email protected]>
…odeql into asgerf/compare-perf-view
The snippet seems to have been copied from 'findOtherQueryToCompare' where it makes sense, but in the context of a performance comparison we don't need this restriction.
Thanks for the review @aeisenberg! I've responded to all comments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for addressing my comments.
After you merge, you can do a release. If you don't feel comfortable doing a release, then send a message to the internal slack channel and we can help you.
}; | ||
} | ||
|
||
protected onPanelDispose(): void {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see how onPanelDispose
is called in the super class. Your implementation here is fine.
if (prefix != null) { | ||
result.push(prefix.abbreviate()); | ||
result.push("::"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine by me. I can understand your perspective even if it is not how I would have written it. And it doesn't seem incorrect to me.
Thanks for the review! I've merged for now, and will see if I can do a release. |
Adds the 'Compare Performance' UI from the hackathon.
Activate via right-clicking on a query history item
Shows overview of predicate evaluation costs
Click a predicate to show its pipeline(s) and tuple counts per step
Changes since the hackathon:
useMemo
and moved some state into subcomponents where a state change cause as much re-rendering.Despite my attempts at cleaning the commit history, it might actually be easiest to review as one giant diff.